package com.dlc.garbagerecyclebox;

import android.content.Context;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;

import com.dlc.commonbiz.base.DlcLogger;
import com.dlc.commonbiz.base.callback.CommonCallback;
import com.dlc.commonbiz.base.callback.DataPackCallback;
import com.dlc.commonbiz.base.exception.ApiException;
import com.dlc.commonbiz.base.exception.ApiExceptionCode;
import com.dlc.commonbiz.base.exception.BaseSerialPortException;
import com.dlc.commonbiz.base.exception.DlcSerialPortException;
import com.dlc.commonbiz.base.serialport.CmdPack;
import com.dlc.commonbiz.base.serialport.DataPack;
import com.dlc.commonbiz.base.serialport.SerialPortService;
import com.dlc.commonbiz.base.serialport.SerialPortServiceProxy;
import com.dlc.commonbiz.base.serialport.ServiceType;
import com.dlc.commonbiz.base.serialport.bean.InitSerialPortBean;
import com.dlc.commonbiz.base.serialport.bean.InitSerialPortGrbBean;
import com.dlc.commonbiz.base.serialport.callback.AsyncDataCallback;
import com.dlc.commonbiz.base.serialport.callback.SendResultCallback;
import com.dlc.commonbiz.base.serialport.callback.SerialPortCallback;
import com.dlc.commonbiz.base.serialport.utils.ByteUtil;
import com.dlc.commonbiz.base.util.BaseLog;
import com.dlc.commonbiz.base.util.GsonUtil;
import com.dlc.commonbiz.base.util.SharedPreferencesUtil;
import com.dlc.garbagerecyclebox.bean.DeliveryInfoBean;
import com.dlc.garbagerecyclebox.bean.DeviceInfoBean;
import com.dlc.garbagerecyclebox.bean.HeartBeatBean;
import com.dlc.garbagerecyclebox.bean.ManageMaintainCommandBean;
import com.dlc.garbagerecyclebox.bean.ManageMaintainInfoBean;
import com.dlc.garbagerecyclebox.bean.RecyclingCommandBean;
import com.dlc.garbagerecyclebox.bean.RecyclingInfoBean;
import com.dlc.garbagerecyclebox.bean.RecyclingResultBean;
import com.dlc.garbagerecyclebox.callback.GarbageRecyclerBoxCmdCallback;
import com.dlc.garbagerecyclebox.callback.GarbageRecyclerBoxDeliveryCallback;
import com.dlc.garbagerecyclebox.callback.GarbageRecyclerBoxRecyclingCallback;
import com.dlc.garbagerecyclebox.callback.GarbageRecyclerBoxRecyclingHeartCallback;
import com.dlc.garbagerecyclebox.exception.DlcVisionSerialPortException;
import com.dlc.garbagerecyclebox.log.GarbageRecycleBoxLogFactory;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author :      fangbingran
 * @aescription : 垃圾回收箱子命令代理工具
 * @date :        2019/07/26  14:16
 */
public class GarbageRecyclerBoxCmdProxy {
    /**
     * 当前回收
     */
    private final Map<String, RecyclingCommandBean> mapRecycling = new ArrayMap<>();
    /**
     * 当前维护管理
     */
    private ArrayMap<String, ManageMaintainCommandBean> mapManageMaintain = new ArrayMap<>();

    private static class InstanceGarbageRecyclerBoxProxy {
        private static final GarbageRecyclerBoxCmdProxy INSTANCE = new GarbageRecyclerBoxCmdProxy();
    }

    public static GarbageRecyclerBoxCmdProxy get() {
        return InstanceGarbageRecyclerBoxProxy.INSTANCE;
    }

    private GarbageRecyclerBoxDeliveryCallback mGarbageRecyclerBoxDeliveryCallback;
    private GarbageRecyclerBoxCmdCallback mCallback;
    private GarbageRecyclerBoxCmdCallback tempCallback;

    public void init(Context context, InitSerialPortGrbBean initSerialPortGrbBean, InitSerialPortGrbBean initVisionSerialPortGrbBean,
                     final GarbageRecyclerBoxCmdCallback garbageRecyclerBoxCmdCallback) {
        this.mCallback = garbageRecyclerBoxCmdCallback;
        SharedPreferencesUtil.init(context);
        close();
        initSerialPortGrbBean(initSerialPortGrbBean);
        initVisionSerialPortGrbBean(initVisionSerialPortGrbBean);
    }

    public void init(Context context, InitSerialPortGrbBean initSerialPortGrbBean,
                     final GarbageRecyclerBoxCmdCallback garbageRecyclerBoxCmdCallback) {
        this.mCallback = garbageRecyclerBoxCmdCallback;
        SharedPreferencesUtil.init(context);
        close();
        initSerialPortGrbBean(initSerialPortGrbBean);
    }

    public void initVisionSerialPortGrbBean(InitSerialPortGrbBean initVisionSerialPortGrbBean) {
        if (initVisionSerialPortGrbBean == null) {
            return;
        }
        List<byte[]> heartVisionCommand = new ArrayList<>();
        heartVisionCommand.add(
                new byte[]{GarbageRecyclerBoxProtocol.CMD_MANAGE_MAINTAIN, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_PHOTO_RECOGNITION});
        InitSerialPortBean grbVisionInitSerialPortBean =
                new InitSerialPortBean(ServiceType.AsyncServices, initVisionSerialPortGrbBean.getDeviceAddress(),
                        initVisionSerialPortGrbBean.getBaudRate(), true, heartVisionCommand);
        grbVisionInitSerialPortBean.setServiceName("async-vision-services-thread");
        SerialPortService grbVisionSerialPortService = new SerialPortService(grbVisionInitSerialPortBean, new AsyncDataCallback() {
            @Override
            public boolean checkData(byte[] received, int size, DataPackCallback dataPackCallback) {
                return GarbageRecyclerBoxHandleDataPack.handleDataPack(byteBuffer, received, size, dataPackCallback);
            }

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            @Override
            public void onActivelyReceivedCommand(byte[] allPackData, byte[] data, byte[] command) {
                HeartBeatBean deviceBean = GarbageRecyclerBoxHandleDataPack.getVisionHeartBeatBean(allPackData, data, command);
                if (mGarbageRecyclerBoxDeliveryCallback != null) {
                    mGarbageRecyclerBoxDeliveryCallback.photoRecognition(deviceBean.getDeviceInfoBean().getCmdCodeNumber());
                    return;
                }
                if (mCallback != null) {
                    mCallback.heatVisionData();
                }
            }
        }, new SerialPortCallback() {
            @Override
            public void onOpenError(String deviceAddress, int baudRate, ApiException dLCException) {
                if (mCallback != null) {
                    mCallback.onError(new DlcVisionSerialPortException(deviceAddress, baudRate, dLCException));
                }
                if (tempCallback != null) {
                    tempCallback.onError(new DlcVisionSerialPortException(deviceAddress, baudRate, dLCException));
                }
            }

            @Override
            public void onOpenSuccess() {
                if (mCallback != null) {
                    mCallback.onOpenVisionSerialPortSuccess();
                }
                if (tempCallback != null) {
                    tempCallback.onOpenVisionSerialPortSuccess();
                }
                GarbageRecycleBoxLogFactory.info("视觉模块串口打开成功!");
            }
        });
        SerialPortServiceProxy.get().add("GarbageRecyclerBoxVision", grbVisionSerialPortService);
    }

    public void initSerialPortGrbBean(InitSerialPortGrbBean initSerialPortGrbBean) {
        if (initSerialPortGrbBean == null) {
            return;
        }
        List<byte[]> heartCommand = new ArrayList<>();
        heartCommand.add(new byte[]{GarbageRecyclerBoxProtocol.CMD_HEART_BEAT, GarbageRecyclerBoxProtocol.CMD_ZERO});
        InitSerialPortBean initSerialPortBean =
                new InitSerialPortBean(ServiceType.AsyncServices, initSerialPortGrbBean.getDeviceAddress(), initSerialPortGrbBean.getBaudRate(), true,
                        heartCommand);
        initSerialPortBean.setServiceName("async-services-thread");
        SerialPortService grbSerialPortService = new SerialPortService(initSerialPortBean, new AsyncDataCallback() {
            @Override
            public boolean checkData(byte[] received, int size, DataPackCallback dataPackCallback) {
                return GarbageRecyclerBoxHandleDataPack.handleDataPack(byteBuffer, received, size, dataPackCallback);
            }

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            @Override
            public void onActivelyReceivedCommand(byte[] allPackData, byte[] data, byte[] command) {
                handleHeatData(allPackData, data, command);
            }
        }, new SerialPortCallback() {
            @Override
            public void onOpenError(String deviceAddress, int baudRate, ApiException dLCException) {
                if (mCallback != null) {
                    mCallback.onError(new DlcSerialPortException(deviceAddress, baudRate, dLCException));
                }
                if (tempCallback != null) {
                    tempCallback.onError(new DlcSerialPortException(deviceAddress, baudRate, dLCException));
                }
            }

            @Override
            public void onOpenSuccess() {
                if (mCallback != null) {
                    mCallback.onOpenSerialPortSuccess();
                }
                if (tempCallback != null) {
                    tempCallback.onOpenSerialPortSuccess();
                }
            }
        });
        SerialPortServiceProxy.get().add("GarbageRecyclerBox", grbSerialPortService);
    }

    public void reConnect(Context context, InitSerialPortGrbBean initSerialPortGrbBean, InitSerialPortGrbBean initVisionSerialPortGrbBean,
                          GarbageRecyclerBoxCmdCallback tempCallback) {
        this.tempCallback = tempCallback;
        init(context, initSerialPortGrbBean, initVisionSerialPortGrbBean, mCallback);
    }

    public void reConnect(Context context, InitSerialPortGrbBean initSerialPortGrbBean,
                          GarbageRecyclerBoxCmdCallback tempCallback) {
        this.tempCallback = tempCallback;
        init(context, initSerialPortGrbBean, mCallback);
    }

    public void setTempCallback(GarbageRecyclerBoxCmdCallback tempCallback) {
        this.tempCallback = tempCallback;
    }

    public void close() {
        cancelManageMaintainCommand();
        cancelRecyclingCommand();
        SerialPortServiceProxy.get().closeSerialPort();
    }

    private synchronized void handleHeatData(byte[] allPackData, byte[] data, byte[] command) {
        HeartBeatBean deviceBean = GarbageRecyclerBoxHandleDataPack.getHeartBeatBean(allPackData, data, command);
        if (deviceBean != null) {
            BaseLog.print(deviceBean.toString());
            if (deliveryProcess(deviceBean.getDeliveryInfoBean())) {
                return;
            }
            if (recyclingProcess(deviceBean.getRecyclingInfoBean())) {
                return;
            }
            if (manageMaintainProcess(deviceBean.getManageMaintainInfoBean())) {
                return;
            }
            if (mCallback != null) {
                mCallback.heatData(deviceBean);
            }
            if (tempCallback != null) {
                tempCallback.heatData(deviceBean);
            }
        }
    }

    public void sendVision(CmdPack cmdPack, SendResultCallback sendResultCallback) {
        SerialPortServiceProxy.get().send("GarbageRecyclerBoxVision", cmdPack, sendResultCallback);
    }

    public void send(CmdPack cmdPack, SendResultCallback sendResultCallback) {
        SerialPortServiceProxy.get().send("GarbageRecyclerBox", cmdPack, sendResultCallback);
    }

    public void setIsShowLog(boolean isShowLog) {
        BaseLog.setIsShowLog(isShowLog);
    }

    public void setIDlcLogger(DlcLogger dlcLogger) {
        GarbageRecycleBoxLogFactory.createLogger(dlcLogger);
    }

    private boolean deliveryProcess(DeliveryInfoBean deliveryInfoBean) {
        if (deliveryInfoBean != null) {
            if (mDestinationAddress == deliveryInfoBean.getDeviceAddress()) {
                if (mGarbageRecyclerBoxDeliveryCallback != null) {
                    mGarbageRecyclerBoxDeliveryCallback.onSuccess(deliveryInfoBean);
                    return true;
                }
            }
        }
        return false;
    }

    private boolean recyclingProcess(RecyclingInfoBean recyclingInfoBean) {
        if (recyclingInfoBean != null) {
            CommonCallback<RecyclingInfoBean> recyclingCallback = getRecyclingCommonCallback(recyclingInfoBean.getDeviceAddress());
            if (recyclingCallback != null) {
                recyclingCallback.onSuccess(recyclingInfoBean);
                if (recyclingInfoBean.isDeliveryCompleted()) {
                    removeRecycling(recyclingInfoBean.getDeviceAddress());
                }
                return true;
            }

            if (mGarbageRecyclerBoxRecyclingHeartCallback != null) {
                mGarbageRecyclerBoxRecyclingHeartCallback.complete(recyclingInfoBean);
            }
        }
        return false;
    }

    private GarbageRecyclerBoxRecyclingHeartCallback mGarbageRecyclerBoxRecyclingHeartCallback;

    /**
     * 拦截心跳的回收信息
     *
     * @param garbageRecyclerBoxRecyclingHeartCallback
     */
    public void setGarbageRecyclerBoxRecyclingHeartCallback(GarbageRecyclerBoxRecyclingHeartCallback garbageRecyclerBoxRecyclingHeartCallback) {
        mGarbageRecyclerBoxRecyclingHeartCallback = garbageRecyclerBoxRecyclingHeartCallback;
    }

    private boolean manageMaintainProcess(ManageMaintainInfoBean manageMaintainInfoBean) {
        if (manageMaintainInfoBean != null) {
            String key = manageMaintainInfoBean.getDeviceAddress() + "_" + manageMaintainInfoBean.getStrDeliveryCmd();
            if (manageMaintainInfoBean.isSwitchUpperHatchDoor() && manageMaintainInfoBean.getSwitchUpperHatchDoorStatus() != null) {
                key = key + "_" + GarbageRecyclerBoxCmdFactory.getSwitchUpperHatchDoorCommandData(
                        manageMaintainInfoBean.getSwitchUpperHatchDoorStatus().getStatus());
            } else if (manageMaintainInfoBean.isIOPortControl() && manageMaintainInfoBean.getIoPortControlStatus() != null) {
                key = key + "_" + GarbageRecyclerBoxCmdFactory.ioPortControlCommand(manageMaintainInfoBean.getIoPortControlStatus().getIOType(),
                        manageMaintainInfoBean.getIoPortControlStatus().getSwitchType());
            } else if (manageMaintainInfoBean.isOpenCloseConveyorBelt() && manageMaintainInfoBean.getConveyorBeltStatus() != null) {
                key = key + "_" + GarbageRecyclerBoxCmdFactory.conveyorBeltCommand(manageMaintainInfoBean.getConveyorBeltStatus().getStartupStatus());
            }
            if (mapManageMaintain.containsKey(key) && mapManageMaintain.get(key) != null) {
                ManageMaintainCommandBean manageMaintainCommandBean = mapManageMaintain.get(key);
                if (manageMaintainCommandBean != null && manageMaintainCommandBean.isEqualsNumber(manageMaintainInfoBean.getCmdCodeNumber())) {
                    if (manageMaintainCommandBean.getCommonCallback() != null) {
                        manageMaintainCommandBean.getCommonCallback().onSuccess(manageMaintainInfoBean);
                    }
                    if (manageMaintainInfoBean.getExecutionStatus() != null && manageMaintainInfoBean.getExecutionStatus().isExecutionCompletion()) {
                        removeManageMaintain(key);
                    }
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 查询命令
     *
     * @param destinationAddress
     * @return
     */
    public void queryCommand(int destinationAddress, final CommonCallback<HeartBeatBean> iCommonCallback) {
        byte[] cmd = GarbageRecyclerBoxCmdFactory.queryCommand(destinationAddress);
        byte[] checkCommand = new byte[]{GarbageRecyclerBoxProtocol.CMD_QUERY, GarbageRecyclerBoxProtocol.CMD_ZERO};
        List<byte[]> checkCommands = new ArrayList<>();
        checkCommands.add(checkCommand);
        CmdPack cmdPack = new CmdPack(destinationAddress, cmd, checkCommands);
        cmdPack.setWaitOutTime(600);
        send(cmdPack, new SendResultCallback() {
            @Override
            public void onStart(CmdPack cmdPack) {
                if (iCommonCallback != null) {
                    iCommonCallback.onStart(cmdPack);
                }
            }

            @Override
            public void onSuccess(DataPack dataPack) {
                if (iCommonCallback != null) {
                    iCommonCallback.onSuccess(
                            GarbageRecyclerBoxHandleDataPack.getHeartBeatBean(dataPack.getAllPackData(), dataPack.getData(), dataPack.getCommand()));
                }
            }

            @Override
            public void onFailed(BaseSerialPortException dLCException) {
                if (iCommonCallback != null) {
                    iCommonCallback.onFailed(dLCException);
                }
            }
        });
    }

    private int mDestinationAddress = 0;

    /**
     * 投递
     *
     * @param destinationAddress
     * @return
     */
    public void deliveryCommand(final int destinationAddress, @DeliverySwitchType int deliveryType) {
        mDestinationAddress = destinationAddress;
        int number = GarbageRecyclerBoxCmdFactory.addNumber(destinationAddress);
        byte[] cmd = GarbageRecyclerBoxCmdFactory.deliveryCommand(destinationAddress, number, deliveryType);
        byte[] checkCommand = new byte[]{GarbageRecyclerBoxProtocol.CMD_DELIVERY, GarbageRecyclerBoxProtocol.CMD_ZERO};
        List<byte[]> checkCommands = new ArrayList<>();
        checkCommands.add(checkCommand);
        final CmdPack cmdPack = new CmdPack(destinationAddress, cmd, checkCommands);
        send(cmdPack, new SendResultCallback() {
            @Override
            public void onStart(CmdPack cmdPack) {
                if (mGarbageRecyclerBoxDeliveryCallback != null) {
                    mGarbageRecyclerBoxDeliveryCallback.onStart(cmdPack);
                }
            }

            @Override
            public void onSuccess(DataPack dataPack) {
                if (mGarbageRecyclerBoxDeliveryCallback != null) {

                    HeartBeatBean deviceBean =
                            GarbageRecyclerBoxHandleDataPack.getHeartBeatBean(dataPack.getAllPackData(), dataPack.getData(), dataPack.getCommand());
                    if (deviceBean != null && deviceBean.getDeliveryInfoBean() != null) {
                        if (mDestinationAddress == deviceBean.getDeviceAddress()) {
                            mGarbageRecyclerBoxDeliveryCallback.onSuccess(deviceBean.getDeliveryInfoBean());
                        } else {
                            mGarbageRecyclerBoxDeliveryCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.GARBAGE_RECYCLE_BOX_ERROR,
                                    "返回的设备id不一致:访问设备id：" + destinationAddress + "接收数据：" + GsonUtil.getInstance().parseObjToJsonStr(deviceBean),
                                    deviceBean.getDeviceAddress()));
                        }
                    } else {
                        mGarbageRecyclerBoxDeliveryCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.GARBAGE_RECYCLE_BOX_ERROR,
                                "返回的命令不是投递命令:" + GsonUtil.getInstance().parseObjToJsonStr(deviceBean), deviceBean.getDeviceAddress()));
                    }
                }
            }

            @Override
            public void onFailed(BaseSerialPortException dLCException) {
                if (mGarbageRecyclerBoxDeliveryCallback != null) {
                    mGarbageRecyclerBoxDeliveryCallback.onFailed(dLCException);
                }
            }
        });
    }

    /**
     * 取消投递回调
     *
     * @return
     */
    public void removeGarbageRecyclerBoxDeliveryCallback() {
        mGarbageRecyclerBoxDeliveryCallback = null;
    }

    /**
     * 设置投递回调
     *
     * @return
     */
    public void setGarbageRecyclerBoxDeliveryCallback(GarbageRecyclerBoxDeliveryCallback garbageRecyclerBoxDeliveryCallback) {
        mGarbageRecyclerBoxDeliveryCallback = garbageRecyclerBoxDeliveryCallback;
    }

    /**
     * 取消回收命令
     *
     * @return
     */
    public void cancelRecyclingCommand() {
        if (mapRecycling.size() == 0) {
            return;
        }
        for (Iterator<Map.Entry<String, RecyclingCommandBean>> it = mapRecycling.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, RecyclingCommandBean> item = it.next();
            if (item != null) {
                it.remove();
            }
        }
    }

    /**
     * 取消管理维护命令
     *
     * @return
     */
    public void cancelManageMaintainCommand() {
        if (mapManageMaintain == null || mapManageMaintain.size() == 0) {
            return;
        }
        for (Iterator<Map.Entry<String, ManageMaintainCommandBean>> it = mapManageMaintain.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, ManageMaintainCommandBean> item = it.next();
            if (item != null) {
                it.remove();
            }
        }
    }


    private void removeManageMaintain(String key) {
        for (Iterator<Map.Entry<String, ManageMaintainCommandBean>> it = mapManageMaintain.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, ManageMaintainCommandBean> item = it.next();
            if (TextUtils.equals(key, item.getKey())) {
                it.remove();
            }
        }
    }


    public void recyclingCommand(int address, RecyclingResultBean recyclingResultBean, final GarbageRecyclerBoxRecyclingCallback iCommonCallback) {
        recyclingCommand(address, new CommonCallback<RecyclingInfoBean>() {
            @Override
            public void onStart(CmdPack cmdPack) {
                if (iCommonCallback != null) {
                    iCommonCallback.onStart(cmdPack);
                }
            }

            @Override
            public void onSuccess(RecyclingInfoBean recyclingInfoBean) {
                Log.d("recyclingCommand_aaa", recyclingInfoBean.toString());
                if (recyclingResultBean != null) {
                    recyclingResultBean.handleSuccess(recyclingInfoBean);
                }
                if (iCommonCallback != null) {
                    Log.d("recyclingCommand_aaa", recyclingResultBean.toString());
                    iCommonCallback.complete(recyclingResultBean);
                }
            }

            @Override
            public void onFailed(BaseSerialPortException e) {
                if (recyclingResultBean != null) {
                    recyclingResultBean.handleException(e);
                }
                Log.d("recyclingCommand_aaa_ff", e.toString());
                if (iCommonCallback != null) {
                    iCommonCallback.complete(recyclingResultBean);
                }
            }
        });
    }

    /**
     * 支持多个回收
     *
     * @param list
     * @param iCommonCallback
     */
    public void recycling(List<Integer> list, final GarbageRecyclerBoxRecyclingCallback iCommonCallback) {
        if (list == null || list.size() == 0) {
            throw new ApiException(ApiExceptionCode.GARBAGE_RECYCLE_BOX_ERROR, "回收箱子命令不能为空");
        }
        RecyclingResultBean recyclingResultBean = new RecyclingResultBean(list);
        for (int i = 0; i < list.size(); i++) {
            recyclingCommand(list.get(i), recyclingResultBean, iCommonCallback);
        }
    }

    private void setRecyclingCommand(final int destinationAddress, int number,
                                     final CommonCallback<RecyclingInfoBean> iCommonCallback) {
        RecyclingCommandBean recyclingCommandBean = new RecyclingCommandBean();
        recyclingCommandBean.setCommonCallback(iCommonCallback);
        recyclingCommandBean.setNumber(number);
        recyclingCommandBean.setDestinationAddress(destinationAddress);
        String key = destinationAddress + "_box";
        synchronized (mapRecycling) {
            mapRecycling.put(key, recyclingCommandBean);
        }
    }

    private CommonCallback<RecyclingInfoBean> getRecyclingCommonCallback(final int destinationAddress) {
        String key = destinationAddress + "_box";
        synchronized (mapRecycling) {
            if (mapRecycling.containsKey(key)) {
                RecyclingCommandBean recyclingCommandBean = mapRecycling.get(key);
                if (recyclingCommandBean != null && recyclingCommandBean.getCommonCallback() != null) {
                    return recyclingCommandBean.getCommonCallback();
                }
            }
        }
        return null;
    }

    private RecyclingCommandBean getRecyclingCommandBean(final int destinationAddress) {
        String key = destinationAddress + "_box";
        synchronized (mapRecycling) {
            if (mapRecycling.containsKey(key)) {
                RecyclingCommandBean recyclingCommandBean = mapRecycling.get(key);
                if (recyclingCommandBean != null) {
                    return recyclingCommandBean;
                }
            }
        }
        return null;
    }

    private void removeRecycling(int destinationAddress) {
        String key = destinationAddress + "_box";
        for (Iterator<Map.Entry<String, RecyclingCommandBean>> it = mapRecycling.entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, RecyclingCommandBean> item = it.next();
            if (TextUtils.equals(key, item.getKey())) {
                it.remove();
            }
        }
    }

    /**
     * 回收
     *
     * @param destinationAddress
     * @return
     */
    public void recyclingCommand(final int destinationAddress, final CommonCallback<RecyclingInfoBean> iCommonCallback) {
        int number = GarbageRecyclerBoxCmdFactory.addNumber(destinationAddress);
        setRecyclingCommand(destinationAddress, number, iCommonCallback);
        byte[] cmd = GarbageRecyclerBoxCmdFactory.recyclingCommand(destinationAddress, number);
        byte[] checkCommand = new byte[]{GarbageRecyclerBoxProtocol.CMD_RECYCLING, GarbageRecyclerBoxProtocol.CMD_ZERO};
        List<byte[]> checkCommands = new ArrayList<>();
        checkCommands.add(checkCommand);
        final CmdPack cmdPack = new CmdPack(destinationAddress, cmd, checkCommands);
        cmdPack.setSendWaitTime(500);
        send(cmdPack, new SendResultCallback() {
            @Override
            public void onStart(CmdPack cmdPack) {
                CommonCallback<RecyclingInfoBean> commonCallback = getRecyclingCommonCallback(cmdPack.getDestinationAddress());
                if (commonCallback != null) {
                    commonCallback.onStart(cmdPack);
                }
            }

            @Override
            public void onSuccess(DataPack dataPack) {
                int deviceAddress = ByteUtil.byteToInt(ByteUtil.getBytes(dataPack.getAllPackData(), GarbageRecyclerBoxProtocol.DEVICE_ADDRESS_INDEX,
                        GarbageRecyclerBoxProtocol.DEVICE_ADDRESS_IEN));
                HeartBeatBean heartBeatBean =
                        GarbageRecyclerBoxHandleDataPack.getHeartBeatBean(dataPack.getAllPackData(), dataPack.getData(), dataPack.getCommand());
                    if (heartBeatBean != null && heartBeatBean.getRecyclingInfoBean() != null) {
                    RecyclingCommandBean recyclingCommandBean = getRecyclingCommandBean(deviceAddress);
                    CommonCallback<RecyclingInfoBean> commonCallback = getRecyclingCommonCallback(deviceAddress);
                    RecyclingInfoBean recyclingInfoBean = heartBeatBean.getRecyclingInfoBean();
                    if (recyclingCommandBean != null) {
                        if (recyclingInfoBean.getCmdCodeNumber() == recyclingCommandBean.getNumber()) {
                            if (commonCallback != null) {
                                commonCallback.onSuccess(heartBeatBean.getRecyclingInfoBean());
                            }
                            if (heartBeatBean.getRecyclingInfoBean().isDeliveryCompleted()) {
                                removeRecycling(deviceAddress);
                            }
                        } else {
                            recyclingCommand(recyclingCommandBean.getDestinationAddress(), recyclingCommandBean.getCommonCallback());
                        }
                    }

                } else {
                    CommonCallback<RecyclingInfoBean> recyclingCallback = getRecyclingCommonCallback(deviceAddress);
                    if (recyclingCallback != null) {
                        recyclingCallback.onFailed(new BaseSerialPortException(ApiExceptionCode.GARBAGE_RECYCLE_BOX_ERROR,
                                "返回的命令不是投递命令:" + GsonUtil.getInstance().parseObjToJsonStr(heartBeatBean), heartBeatBean.getDeviceAddress()));
                    }
                    removeRecycling(deviceAddress);
                }

            }

            @Override
            public void onFailed(BaseSerialPortException dLCException) {
                CommonCallback<RecyclingInfoBean> recyclingCallback = getRecyclingCommonCallback(dLCException.getAddress());
                if (recyclingCallback != null) {
                    recyclingCallback.onFailed(dLCException);
                }
                removeRecycling(dLCException.getAddress());
            }
        });
    }

    private boolean checkRecycling(String key) {
        if (mapRecycling.containsKey(key)) {
            RecyclingCommandBean recyclingCommandBean = mapRecycling.get(key);
            if (recyclingCommandBean != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * 开关上舱门命令
     *
     * @param destinationAddress
     * @return
     */
    public void switchUpperHatchDoorCommand(final int destinationAddress, @SwitchType final int switchType,
                                            final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key = destinationAddress
                + "_"
                + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_WEIGHING_BEFORE_OPEN_DOOR})
                + "_"
                + GarbageRecyclerBoxCmdFactory.getSwitchUpperHatchDoorCommandData(switchType);
        sendManageMaintain("正在开关上舱门中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_WEIGHING_BEFORE_OPEN_DOOR,
                GarbageRecyclerBoxCmdFactory.getSwitchUpperHatchDoorCommandData(switchType), key, iCommonCallback);
    }

    /**
     * 关上舱门命令
     *
     * @param destinationAddress
     * @return
     */
    public void shutUpperHatchDoor(final int destinationAddress,
                                   final CommonCallback<ManageMaintainInfoBean> commonCallback) {
        queryCommand(destinationAddress, new CommonCallback<HeartBeatBean>() {
            @Override
            public void onStart(CmdPack cmdPack) {
                if (commonCallback != null) {
                    commonCallback.onStart(cmdPack);
                }
            }

            @Override
            public void onSuccess(HeartBeatBean heartBeatBean) {
                DeviceInfoBean.SensorStatusBean sensorStatusBean = heartBeatBean.getSensorStatusBean();
                if (sensorStatusBean != null) {
                    if (!sensorStatusBean.isELockUpperLimit()
                            && !sensorStatusBean.isELockUpperLowerLimit()
                            && !sensorStatusBean.isUpperHatchLimit()
                            && !sensorStatusBean.isUpperHatchLowerLimit()
                            && !sensorStatusBean.isLeftClasp()
                            && !sensorStatusBean.isRightClasp()) {
                        return;
                    }
                    //投递门没关门
                    GarbageRecyclerBoxCmdProxy.get().switchUpperHatchDoorCommand(destinationAddress, SwitchType.Shut, null);
                    if (commonCallback != null) {
                        commonCallback.onSuccess(null);
                    }
                } else {
                    if (commonCallback != null) {
                        commonCallback.onSuccess(null);
                    }
                }
            }

            @Override
            public void onFailed(BaseSerialPortException dLCException) {
                if (commonCallback != null) {
                    commonCallback.onFailed(dLCException);
                }
            }
        });
    }

    /**
     * 关下舱门命令
     *
     * @param destinationAddress
     * @return
     */
    public void penLowerHatchDoorCommand(final int destinationAddress, final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key =
                destinationAddress + "_" + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_OPEN_HATCH_DOOR});
        sendManageMaintain("正在关下舱门中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_OPEN_HATCH_DOOR, "", key, iCommonCallback);
    }

    /**
     * IO口控制命令
     *
     * @param destinationAddress
     * @return
     */
    public void ioPortControlCommand(int destinationAddress, @IOType int iOType, @SwitchType int switchType,
                                     final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        
        String key = destinationAddress
                + "_"
                + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_FIRST_PHOTOELECTRIC_TRIGGER})
                + "_"
                + GarbageRecyclerBoxCmdFactory.ioPortControlCommand(iOType, switchType);
        Log.d("lgq","开灯命令100-00000--22---"+key+"......."+switchType);
        sendManageMaintain("正在执行IO口控制中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_FIRST_PHOTOELECTRIC_TRIGGER,
                GarbageRecyclerBoxCmdFactory.ioPortControlCommand(iOType, switchType), key, iCommonCallback);
    }

    /**
     * 传送带命令
     *
     * @param destinationAddress
     * @return
     */
    public void conveyorBeltCommand(int destinationAddress, @ControlConveyorBeltType int controlConveyorBeltType,
                                    final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key = destinationAddress
                + "_"
                + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_TWO_PHOTOELECTRIC_TRIGGER})
                + "_"
                + GarbageRecyclerBoxCmdFactory.conveyorBeltCommand(controlConveyorBeltType);
        sendManageMaintain("正在执行传送带命令中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_TWO_PHOTOELECTRIC_TRIGGER,
                GarbageRecyclerBoxCmdFactory.conveyorBeltCommand(controlConveyorBeltType), key, iCommonCallback);
    }

    /**
     * 拍照识别命令
     *
     * @param destinationAddress
     * @return
     */
    public void photoRecognitionCommand(int destinationAddress, final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key = destinationAddress + "_" + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_PHOTO_RECOGNITION});
        sendManageMaintain("正在执行拍照识别命令中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_PHOTO_RECOGNITION, "", key,
                iCommonCallback);
    }

    /**
     * 电子秤置零命令
     *
     * @param destinationAddress
     * @return
     */
    public void electronicScaleZeroCommand(int destinationAddress, final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key =
                destinationAddress + "_" + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_THREE_PHOTOELECTRIC_TRIGGER});
        sendManageMaintain("正在执行电子秤置零命令中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_THREE_PHOTOELECTRIC_TRIGGER, "", key,
                iCommonCallback);
    }

    /**
     * 电子秤零点标定命令
     *
     * @param destinationAddress
     * @return
     */
    public void electronicScaleZeroCalibrationCommand(int destinationAddress, final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key = destinationAddress + "_" + ByteUtil.bytes2HexStr(
                new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_RETURN_FIRST_PHOTOELECTRIC_TRIGGER});
        sendManageMaintain("正在执行电子秤零点标定命令中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_RETURN_FIRST_PHOTOELECTRIC_TRIGGER,
                "", key, iCommonCallback);
    }

    /**
     * 电子秤重量标定命令
     *
     * @param destinationAddress
     * @return
     */
    public void electronicWeightCalibrationCommand(int destinationAddress, int weight, final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        if (weight > 99999) {
            throw new ApiException(ApiExceptionCode.GARBAGE_RECYCLE_BOX_ERROR, "重量标定不能超过99999");
        }
        String key =
                destinationAddress + "_" + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_WAITING_REMOVAL_EXCEPTION});
        sendManageMaintain("正在执行电子秤重量标定命令中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_WAITING_REMOVAL_EXCEPTION,
                ByteUtil.convertStringAsciiToHex(weight, 5), key, iCommonCallback);
    }

    /**
     * 清空累计数量/重量命令
     *
     * @param destinationAddress
     * @return
     */
    public void emptyAmountCommand(int destinationAddress, final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key =
                destinationAddress + "_" + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_WAITING_REMOVAL_EXCEPTION2});
        sendManageMaintain("正在执行清空累计数量/重量命令中....", destinationAddress, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_WAITING_REMOVAL_EXCEPTION2, "", key,
                iCommonCallback);
    }

    /**
     * 视觉模块拍照识别命令
     *
     * @return
     */
    /**
     * 视觉模块拍照识别命令
     *
     * @return
     */
    public void photoRecognitionToVisionCommand(int number, @PhotoRecognitionType int photoRecognitionToVisionCommand) {
        final byte[] checkCommand =
                new byte[]{GarbageRecyclerBoxProtocol.CMD_MANAGE_MAINTAIN, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_PHOTO_RECOGNITION};
        byte[] cmd = GarbageRecyclerBoxCmdFactory.getManageMaintain(0, GarbageRecyclerBoxProtocol.DeliveryCmd.CMD_PHOTO_RECOGNITION, number,
                GarbageRecyclerBoxCmdFactory.photoRecognitionToVisionCommand(photoRecognitionToVisionCommand));
        List<byte[]> checkCommands = new ArrayList<>();
        checkCommands.add(checkCommand);
        CmdPack cmdPack = new CmdPack(0, cmd, checkCommands);
        sendVision(cmdPack, null);
    }

    private void sendManageMaintain(String tip, final int destinationAddress, byte checkCmd, String data, final String key,
                                    final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        sendManageMaintain(false, tip, destinationAddress, checkCmd, data, key, iCommonCallback);
    }

    /**
     * @param isVision           是否为视觉模块
     * @param tip                提示语
     * @param destinationAddress 地址
     * @param checkCmd           命令
     * @param data               数据内容
     */
    private void sendManageMaintain(boolean isVision, String tip, final int destinationAddress, byte checkCmd, String data, final String key,
                                    final CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        if (checkManageMaintain(key)) {
            GarbageRecycleBoxLogFactory.info(tip);
            return;
        }
        int number = GarbageRecyclerBoxCmdFactory.addNumber(destinationAddress);
        final byte[] checkCommand = new byte[]{GarbageRecyclerBoxProtocol.CMD_MANAGE_MAINTAIN, checkCmd};
        byte[] cmd = GarbageRecyclerBoxCmdFactory.getManageMaintain(destinationAddress, checkCmd, number, data);
        List<byte[]> checkCommands = new ArrayList<>();
        checkCommands.add(checkCommand);
        Log.d("lgq","开灯命令100-00000---33e--"+"......."+ByteUtil.bytes2HexStr(cmd));
        final CmdPack cmdPack = new CmdPack(destinationAddress, cmd, checkCommands);
        if (isVision) {
            sendVision(cmdPack, null);
        } else {
            ManageMaintainCommandBean manageMaintainCommandBean = new ManageMaintainCommandBean();
            manageMaintainCommandBean.setNumber(number);
            manageMaintainCommandBean.setCommonCallback(iCommonCallback);
            manageMaintainCommandBean.setCheckCommand(checkCmd);
            manageMaintainCommandBean.setDestinationAddress(destinationAddress);
            synchronized (mapManageMaintain) {
                mapManageMaintain.put(key, manageMaintainCommandBean);
            }
            send(cmdPack, new SendResultCallback() {
                @Override
                public void onStart(CmdPack cmdPack) {
                    if (iCommonCallback != null) {
                        iCommonCallback.onStart(cmdPack);
                    }
                }

                @Override
                public void onSuccess(DataPack dataPack) {
                    manageMaintainSuccess(key, dataPack);
                }

                @Override
                public void onFailed(BaseSerialPortException dLCException) {
                    manageMaintainFailed(key, dLCException);
                }
            });
        }
    }

    private boolean checkManageMaintain(String key) {
        if (mapManageMaintain.containsKey(key)) {
            for (Iterator<Map.Entry<String, ManageMaintainCommandBean>> it = mapManageMaintain.entrySet().iterator(); it.hasNext(); ) {
                Map.Entry<String, ManageMaintainCommandBean> item = it.next();
                ManageMaintainCommandBean manageMaintainBean = item.getValue();
                if (manageMaintainBean != null) {
                    if (TextUtils.equals(key, item.getKey())
                            && System.currentTimeMillis() - manageMaintainBean.getSysTime() >= 5000) {
                        it.remove();
                    }
                }

            }
        }
        return false;
    }

    private void manageMaintainFailed(String key, BaseSerialPortException dLCException) {
        if (mapManageMaintain.containsKey(key)) {
            ManageMaintainCommandBean manageMaintainCommandBean1 = mapManageMaintain.get(key);
            if (manageMaintainCommandBean1 != null && manageMaintainCommandBean1.getCommonCallback() != null) {
                manageMaintainCommandBean1.getCommonCallback().onFailed(dLCException);
            }
            removeManageMaintain(key);
        }
    }

    private void manageMaintainSuccess(String key, DataPack dataPack) {
        if (mapManageMaintain.containsKey(key)) {
            HeartBeatBean deviceBean =
                    GarbageRecyclerBoxHandleDataPack.getHeartBeatBean(dataPack.getAllPackData(), dataPack.getData(), dataPack.getCommand());
            if (deviceBean != null && deviceBean.getManageMaintainInfoBean() != null) {
                manageMaintainProcess(deviceBean.getManageMaintainInfoBean());
            } else {
                ManageMaintainCommandBean manageMaintainCommandBean1 = mapManageMaintain.get(key);
                if (manageMaintainCommandBean1 != null && manageMaintainCommandBean1.getCommonCallback() != null) {
                    manageMaintainCommandBean1.getCommonCallback()
                            .onFailed(new BaseSerialPortException(ApiExceptionCode.GARBAGE_RECYCLE_BOX_ERROR,
                                    "返回的命令不是对应管理维护命令:" + GsonUtil.getInstance().parseObjToJsonStr(deviceBean),
                                    manageMaintainCommandBean1.getDestinationAddress()));
                }
                removeManageMaintain(key);
            }
        }
    }

    /**
     * 有害垃圾投递命令
     *
     * @param destinationAddress
     * @return
     */
    public void toDeliveryHarmfulWaste(int destinationAddress, CommonCallback<ManageMaintainInfoBean> iCommonCallback) {
        String key =
                destinationAddress + "_" + ByteUtil.bytes2HexStr(new byte[]{GarbageRecyclerBoxProtocol.CMD_OPEN_HARMFUL_WASTE});
        sendManageMaintain("正在有害垃圾投递命令中....", destinationAddress, GarbageRecyclerBoxProtocol.CMD_OPEN_HARMFUL_WASTE, "", key,
                iCommonCallback);
    }
}
